﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace KiDS_Bootstrap
{
	/// <summary>
	/// Predstavlja klijenta koji salje request bilo kom cvoru u sistemu
	/// </summary>
	public unsafe class Client : IDisposable
	{

		private SOCKET _clientSocket;
		private string _address;
		private ushort _port;

		/// <summary>
		/// Klijent za komunikaciju sa odredjenom adresom, na odredjenom portu
		/// </summary>
		/// <param name="address">Adresa na koju se zeli konektovati</param>
		/// <param name="port">Port na koji se treba konektovati</param>
		public Client(string address, ushort port)
		{
			_address = address;
			_port = port;
		}

		/// <summary>
		/// Otvaranje konekcije ka odredjenom portu i adresi
		/// </summary>
		/// <returns>Uspesnost otvaranja konekcije</returns>
		public bool Open()
		{
			WSAData wsaData = new WSAData();
			int startupResult = Native.WSAStartup(/*MAKEWORD(2, 2)*/514, out wsaData);
			if (startupResult == Native.SOCKET_ERROR)
			{
				Console.WriteLine("WSA start-up error code: " + wsaData.ToString());
				return false;
			}

			// [ 1 ] Set-up socket
			_clientSocket = Native.socket(AddressFamily.InterNetworkv4, SocketType.Stream,
							ProtocolType.Tcp);
			if (_clientSocket == Native.INVALID_SOCKET)
			{
				Console.WriteLine("Creating socket: " + Native.WSAGetLastError().ToString());
				return false;
			}

			// [ 2 ] Connect 
			sockaddr_in sockaddr = new sockaddr_in();

			sockaddr.sin_family = Native.AF_INET;
			sockaddr.sin_addr.S_addr = Native.inet_addr(_address);
			sockaddr.sin_port = Native.htons(_port);

			int connectResult = Native.connect(_clientSocket, &sockaddr, Marshal.SizeOf(sockaddr));
			if (connectResult == Native.SOCKET_ERROR)
			{
				Console.WriteLine("Connecting to server: " + Native.WSAGetLastError().ToString());
				return false;
			}
			return true;
		}

		/// <summary>
		/// Enkapsulacija nativne metode za zatvaranje socketa
		/// </summary>
		/// <returns>Uspesnost zatvaranja socketa</returns>
		public bool Close()
		{
			int val = Native.closesocket(_clientSocket);
			return val == 1;
		}

		/// <summary>
		/// Enkapsulacija nativne metode za slanje poruke
		/// </summary>
		/// <param name="message">Poruka za slanje</param>
		/// <returns>Uspesnost slanja poruke</returns>
		public bool SendMessage(string message)
		{
			return Native.SendMessage(message, _clientSocket);
		}

		/// <summary>
		/// Enkapsulacija nativne metode za primanje poruke
		/// </summary>
		/// <returns>Primljenu poruku</returns>
		public string RecieveMessage()
		{
			return Native.RecieveMessage(_clientSocket);
		}

		public void Dispose()
		{
			//Marshal.FreeHGlobal(&_clientSocket);
		}
	}
}
